--[[-------------------------------------------------------------------------------
  Copyright (c) 2008, Naitaeti (Bronzebeard EU, Horde)

  Some ideas and code lifted from pStats by p3lim and LynStats by Lyn
---------------------------------------------------------------------------------]]


--[[-------------------------------------------------------------------------------
	Configuration
---------------------------------------------------------------------------------]]

-- show percentages
local showPerc = true

-- name of the frame to attach to
local frameAttach = "MiniMapTracking"

-- attach anchor
local frameAnchor = "ANCHOR_BOTTOMLEFT"

-- attach x pos
local frameX = 0

-- attach y pos
local frameY = -6

-- button to click to reset the session
local resetButton = "MiddleButton"

-- pass the reset button on to the attached frame?
local blockResetButton = true

-- put your left tooltip color here
local leftColor = { r = 0.82, g = 0.72, b = 0.08 }

-- put your right tooltip color here
local rightColor = { r = 1, g = 1, b = 1 }

-- auto resume (if paused) when gaining xp
local autoresume = true

--[[-------------------------------------------------------------------------------
	Code
---------------------------------------------------------------------------------]]

local naistats = "|cffffff77naiStats|r"

local addon = CreateFrame("Frame", nil, UIParent)
local initialized = false
local realFrame = nil
local oldEnter, oldLeave, oldMouseUp, oldUpdate
local ispaused = false

local naistats_command = function(cmd)
	--DEFAULT_CHAT_FRAME:AddMessage("naiStats command: " .. cmd)
	local ucmd = strupper(cmd)
	if ucmd == "TOGGLE" then
		if ispaused then
			ispaused = false
			DEFAULT_CHAT_FRAME:AddMessage(naistats .. " resumed")
		else
			ispaused = true
			DEFAULT_CHAT_FRAME:AddMessage(naistats .. " paused")
		end
	elseif ucmd == "PAUSE" then
		if not ispaused then
			ispaused = true
			DEFAULT_CHAT_FRAME:AddMessage(naistats .. " paused")
		end
	elseif ucmd == "RESUME" then
		if ispaused then
			DEFAULT_CHAT_FRAME:AddMessage(naistats .. " resumed")
			ispaused = false
		end
	else
		DEFAULT_CHAT_FRAME:AddMessage(naistats .. " unknown command. Command can be TOGGLE, PAUSE or RESUME")
	end
end

-- the allmighty
function addon:new()
	if UnitLevel("player") >= 70 then
		return
	end	

	self:RegisterEvent("CHAT_MSG_COMBAT_XP_GAIN")
	self:RegisterEvent("PLAYER_ENTERING_WORLD")
	self:SetScript("OnEvent", self.event)
	
	SlashCmdList["NAISTATS"] = naistats_command
	SLASH_NAISTATS1 = "/ns"
	SLASH_NAISTATS2 = "/nstats"
end

local lastxp, totalxp, killed, quests = 0, 0, 0, 0
local killsxp, questsxp = 0, 0
local lastkillxp = 0

function addon:hookFrame()
	realFrame:EnableMouse(true)

	oldEnter = realFrame:GetScript("OnEnter")
	oldLeave = realFrame:GetScript("OnLeave")
	oldUpdate = realFrame:GetScript("OnUpdate")
	oldMouseUp = realFrame:GetScript("OnMouseUp")
	realFrame:SetScript("OnEnter", self.enter)
	realFrame:SetScript("OnLeave", self.leave)
	realFrame:SetScript("OnUpdate", self.update)
	realFrame:SetScript("OnMouseUp", self.mouseup)
end

function addon:event(event, ...)
	if event == "PLAYER_ENTERING_WORLD" then
		if not initialized then
			realFrame = getglobal(frameAttach)
			if not realFrame then
				return
			end
			
			initialized = true
			self:hookFrame()
		end
	elseif event == "CHAT_MSG_COMBAT_XP_GAIN" then
		--ChatFrame1:AddMessage("xp gain" .. select(1, ...))
		local txt = ...
		--local mob, xp
		local xp
		for xp in txt:gmatch(".+ dies, you gain (%d+) experience.") do
			lastxp = tonumber(xp)
			lastkillxp = lastxp
			totalxp = totalxp + lastxp
			killsxp = killsxp + lastxp
			killed = killed + 1

			if ispaused and autoresume then
				ispaused = false
				DEFAULT_CHAT_FRAME:AddMessage(naistats .. " autoresumed")
			end
		end
		for xp in txt:gmatch("You gain (%d+) experience.") do
			lastxp = tonumber(xp)
			totalxp = totalxp + lastxp
			questsxp = questsxp + lastxp
			quests = quests + 1
			
			if ispaused and autoresume then
				ispaused = false
				DEFAULT_CHAT_FRAME:AddMessage(naistats .. " autoresumed")
			end
		end
		--ChatFrame1:AddMessage("xp gain " .. lastxp)
	end
end

-- update
local last, total, paused = 0, 0, 0
local texts = 
	{ 
		{ left = "Session time", right = nil },
		{ left = "Paused time", right = nil, hide = true },
		{ left = " ", right = nil },
		{ left = "XP needed", right = nil },
		{ left = "XP remaining", right = nil },
		{ left = "XP rested", right = nil, hide = true },
		{ left = "XP gained", right = nil },
		{ left = "XP per hour", right = nil },
		{ left = "Time left", right = nil },
		{ left = " ", right = nil },
		{ left = "Kills", right = nil },
		{ left = "Avg. XP per kill", right = nil },
		{ left = "XP for last kill", right = nil },
		{ left = "Kills to level", right = nil },
		{ left = " ", right = nil },
		{ left = "Quests delivered", right = nil },
		{ left = "Avg. XP per quest", right = nil },
	}
local tooltip = false

function addon:update(elapsed)
	if oldUpdate then
		oldUpdate(self, elapsed)
	end
	
	last = last + elapsed
	total = total + elapsed
	if ispaused then
		paused = paused + elapsed
	end

	-- moep.
	if last > 1 then
		if UnitLevel("player") >= 70 then
			return
		end
		
		-- xp stuff
		local xp_cur = UnitXP("player")
		local xp_max = UnitXPMax("player")

		local xphour = totalxp / ((total - paused) / 60 / 60)
		local timeleft = 0
		if totalxp > 0 then
			timeleft = (xp_max - xp_cur) / (totalxp / (total - paused))
		end
		local timeh = floor(timeleft / 60 / 60)
		timeleft = timeleft - (timeh * 60 * 60)
		local timem = floor(timeleft / 60)
		timeleft = timeleft - (timem * 60)
		local times = floor(timeleft)
		
		timeleft = total
		local elapsedh = floor(timeleft / 60 / 60)
		timeleft = timeleft - (elapsedh * 60 * 60)
		local elapsedm = floor(timeleft / 60)
		timeleft = timeleft - (elapsedm * 60)
		local elapseds = floor(timeleft)

		local rested = GetXPExhaustion()
		local perc
		
		texts[1].right = format("%02d:%02d.%02d", elapsedh, elapsedm, elapseds) -- Session time
		if paused > 0 then -- paused
			timeleft = paused
			elapsedh = floor(timeleft / 60 / 60)
			timeleft = timeleft - (elapsedh * 60 * 60)
			elapsedm = floor(timeleft / 60)
			timeleft = timeleft - (elapsedm * 60)
			elapseds = floor(timeleft)
			texts[2].hide = false
			texts[2].right = format("%02d:%02d.%02d", elapsedh, elapsedm, elapseds)
		else
			texts[2].hide = true
		end
		texts[4].right = xp_max -- XP needed
		texts[5].right = floor(xp_max - xp_cur) -- XP remaining
		if showPerc then
			perc = floor((xp_max - xp_cur) / xp_max * 100)
			texts[5].right = texts[5].right .. " (" .. perc .. "%)"
		end
		if rested then -- XP rested
			texts[6].right = rested
			if showPerc then
				perc = floor(rested / xp_max * 100)
				texts[6].right = texts[6].right .. " (" .. perc .. "%)"
			end
			texts[6].hide = false
		else
			texts[6].hide = true
		end
		texts[7].right = totalxp -- XP gained
		if showPerc then
			perc = floor(totalxp / xp_max * 100)
			texts[7].right = texts[7].right .. " (" .. perc .. "%)"
		end
		texts[8].right = floor(xphour) -- XP per hour
		if showPerc then
			perc = floor(xphour / xp_max * 100)
			texts[8].right = texts[8].right .. " (" .. perc .. "%)"
		end
		texts[9].right = format("%02d:%02d.%02d", timeh, timem, times) -- Time left
		texts[11].right = killed -- Kills
		if killed > 0 then
			texts[12].right = floor(killsxp / killed) -- Avg. XP per kill
		end
		if lastkillxp > 0 then
			texts[13].right = lastkillxp
			texts[14].right = floor((xp_max - xp_cur) / lastkillxp)
		end
		texts[16].right = quests -- Quests delivered
		if quests > 0 then
			texts[17].right = floor(questsxp / quests) -- Avg. XP per quest
		end

		last = 0
		if tooltip then
			addon:setupTooltip()
		end
	end
end

function addon:setupTooltip()
	GameTooltip:ClearLines()
	GameTooltip:AddLine("naiStats", leftColor.r, leftColor.g, leftColor.b)
	GameTooltip:AddLine(" ")
	for _, entry in pairs(texts) do
		if not entry.hide then
			GameTooltip:AddDoubleLine(entry.left, entry.right, 
				leftColor.r, leftColor.g, leftColor.b, 
				rightColor.r, rightColor.g, rightColor.b)
		end
	end
end

function addon:resetTexts()
	for _, entry in pairs(texts) do
		entry.right = nil
	end
end

function addon:enter()
	if oldEnter then
		oldEnter(self)
	end
	--ChatFrame1:AddMessage("enter")
	if not tooltip and UnitLevel("player") < 70 then
		GameTooltip:SetOwner(realFrame, frameAnchor, frameX, frameY)
		addon:setupTooltip()
		GameTooltip:Show()
		tooltip = true
	end
end

function addon:leave()
	if oldLeave then
		oldLeave(self)
	end
  --ChatFrame1:AddMessage("leave")
	if tooltip then
		tooltip = false
		GameTooltip:Hide()
	end
end

function addon:mouseup(button)
	if oldMouseUp then
		if not blockResetButton or button ~= resetButton then
			oldMouseUp(self, button)
		end
	end
	if button ~= resetButton then
		return
	end
	
	--ChatFrame1:AddMessage("click " .. button)
	lastxp, totalxp, killed, quests = 0, 0, 0, 0
	killsxp, questsxp = 0, 0
	lastkillxp = 0
	total, paused = 0, 0
	addon:resetTexts()
end

-- and... go!
addon:new()